﻿Imports System.Net
Imports System.Text.RegularExpressions
Imports System.ComponentModel
Imports System.Reflection
Imports System.Windows.Threading
Imports System.Web
Imports <xmlns="http://ch.nicovideo.jp/community/co9320">

<Assembly: CLSCompliant(False)> 

Class MainWindow
    Implements IDisposable

    Private Crawler As BackgroundWorker

    Public Shared ReadOnly SubscribeCommand As RoutedCommand = New RoutedCommand("Subscribe", GetType(MainWindow))
    Public Shared ReadOnly DeleteCommand As RoutedCommand = New RoutedCommand("Delete", GetType(MainWindow))

    Public Shared ReadOnly AddStationsCommand As RoutedCommand = New RoutedCommand("AddStations", GetType(MainWindow))
    Public Shared ReadOnly DeleteStationsCommand As RoutedCommand = New RoutedCommand("DeleteStations", GetType(MainWindow))
    Public Shared ReadOnly DeleteKeywordsCommand As RoutedCommand = New RoutedCommand("DeleteKeywords", GetType(MainWindow))
    Public Shared ReadOnly OpenUrisCommand As RoutedCommand = New RoutedCommand("OpenUris", GetType(MainWindow))
    Public Shared ReadOnly CopyUriCommand As RoutedCommand = New RoutedCommand("CopyUri", GetType(MainWindow))
    

    Private Shadows IsLoaded As Boolean
    Private CrawlSettings As New CrawlSettings

#Region "Porperties"
    Private ReadOnly Property Context() As MainWindowDataContext
        Get
            Return DirectCast(Me.DataContext, MainWindowDataContext)
        End Get
    End Property

    Private Shared ReadOnly Property StartupPath() As String
        Get
            Return System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly.Location)
        End Get
    End Property
#End Region

    Private Sub CrawlPages(ByVal preWaitMinute As Integer)

        Crawler = New BackgroundWorker
        Crawler.WorkerReportsProgress = True
        Crawler.WorkerSupportsCancellation = True
        AddHandler Crawler.DoWork, AddressOf PageCrawling
        AddHandler Crawler.ProgressChanged, AddressOf PageCrawlingProgressChanged
        AddHandler Crawler.RunWorkerCompleted, AddressOf PageCrawlingCompleted
        Crawler.RunWorkerAsync(preWaitMinute)

    End Sub

    Private Sub PageCrawling(ByVal sender As Object, ByVal e As DoWorkEventArgs)

        System.Threading.Thread.Sleep(DirectCast(e.Argument, Integer) * 60 * 1000)

        For Each u In Me.CrawlSettings.Uris
            Dim content = GetContent(u)
            Crawler.ReportProgress(0, content)
            System.Threading.Thread.Sleep(500)
        Next

    End Sub

    Private Sub PageCrawlingProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
        Dim content = DirectCast(e.UserState, String)
        Dim isExist As Boolean = False

        Dim pt = Me.CrawlSettings.RegexPattern.Replace(vbLf, "").Trim
        For Each m As Match In Regex.Matches(content, pt, RegexOptions.Singleline)
            If Not m.Success Then
                Continue For
            End If

            Dim community = New Community With { _
                .Id = m.Groups("co_id").Value, _
                .Name = m.Groups("co_name").DecodeValue, _
                .IconUri = New Uri(m.Groups("co_img").Value), _
                .IsOnAir = True, _
                .RecentAirdate = New DateTime(CInt(m.Groups("start_year").Value), CInt(m.Groups("start_month").Value), CInt(m.Groups("start_day").Value), CInt(m.Groups("start_hour").Value), CInt(m.Groups("start_minute").Value), 0)}

            Dim program = New LiveProgram With { _
                .Id = m.Groups("live_id").Value, _
                .Title = m.Groups("live_title").DecodeValue, _
                .Uri = New Uri(m.Groups("live_url").Value), _
                .Content = m.Groups("live_content").DecodeValue.Replace(vbCr, "").Replace(vbLf, ""), _
                .StartDateTime = community.RecentAirdate, _
                .VisitorCount = CInt(m.Groups("visitor_num").Value), _
                .CommentCount = CInt(m.Groups("comment_count").Value), _
                .IsMemberOnly = CBool(m.Groups("member_only").Value <> ""), _
                .Community = community}

            ' LiveProgramList に追加
            Dim existPrograms = From p In Me.Context.LiveProgramList Where p.Id = program.Id
            If existPrograms.Count > 0 Then
                With existPrograms.First
                    .Title = program.Title
                    .VisitorCount = program.VisitorCount
                    .CommentCount = program.CommentCount
                End With
            Else
                Me.Context.LiveProgramList.Add(program)
            End If

            ' 登録コミュが放送してる
            Dim id = program.Community.Id
            Dim existCommunities = From c In Me.Context.CommunityList Where c.Id = id
            If existCommunities.Count > 0 Then
                isExist = True

                ' OnAir, 最近放送日更新, 名前
                existCommunities.First.IsOnAir = True
                existCommunities.First.RecentAirdate = program.StartDateTime
                existCommunities.First.Name = program.Community.Name

            End If

        Next

        LiveProgramListView.Resort()


        If isExist Then
            Alert()
        End If

    End Sub

    Private Sub Alert()

        ' 通知対象の番組
        Dim targets = New List(Of LiveProgram)
        Dim communities = From c In Me.Context.CommunityList Where c.IsOnAir

        For Each c In communities
            Dim id = c.Id
            Dim programs = From p In Me.Context.LiveProgramList Where p.Community.Id = id
            If programs.Count > 0 AndAlso Not Alerter.AlertedProgramIds.Contains(programs.First.Id) Then
                targets.Add(programs.First)
                Alerter.AlertedProgramIds.Add(programs.First.Id) ' 通知済みListに追加
            End If
        Next

        If targets.Count = 0 Then
            Exit Sub
        End If

        Alerter.Alert(targets)

        'Dim settings = Me.Context.UserSettings

        '' Alert Window
        'If settings.AlertWindowEnabled Then
        '    For Each p In targets
        '        Dim window = New AlertWindow(p)
        '        window.Show()
        '    Next
        'End If

        '' Balloon
        'If settings.BalloonEnabled Then

        '    If BalloonTimer Is Nothing Then
        '        BalloonTimer = New DispatcherTimer
        '        AddHandler BalloonTimer.Tick, AddressOf ShowBalloon
        '    End If
        '    If BalloonPlograms.Count = 0 Then
        '        BalloonTimer.Interval = New TimeSpan(1)
        '    End If

        '    For Each p In targets
        '        BalloonPlograms.Enqueue(p)
        '    Next
        '    BalloonTimer.Start()
        'End If

        '' Web
        'If settings.WebOpeningEnabled Then
        '    For Each p In targets
        '        Try
        '            Process.Start(p.Uri.ToString)
        '        Catch ex As Exception
        '            ' Ignore
        '        End Try
        '    Next
        'End If

        '' Sound
        'If settings.SoundEnabled Then
        '    Try
        '        Dim player = New System.Media.SoundPlayer
        '        player.SoundLocation = settings.SoundFile
        '        player.Play()
        '        player.Dispose()
        '    Catch ex As Exception
        '        ' Ignore
        '    End Try
        'End If

    End Sub



    'Private Sub EnableReloadButton(ByVal sender As Object, ByVal e As EventArgs)
    '    'Me.ReloadButton.IsEnabled = True
    '    DirectCast(sender, DispatcherTimer).Stop()
    'End Sub

    Private Sub PageCrawlingCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)

        '' 更新ボタン
        'Dim timer = New DispatcherTimer
        'AddHandler timer.Tick, AddressOf EnableReloadButton
        'timer.Interval = New TimeSpan(0, 0, 10)
        'timer.Start()

        ' 放送終了している登録コミュのOnAir表示をやめる
        Dim communities = From c In Me.Context.CommunityList Where Now.Subtract(c.RecentAirdate).Minutes > 30
        For Each c In communities
            c.IsOnAir = False
        Next

        ' 放送終了している番組を生放送一覧から削除
        ' チェックしている番組は除く
        Dim programs = From p In Me.Context.LiveProgramList Where Now.Subtract(p.StartDateTime).Minutes > 30
        For i = Me.Context.LiveProgramList.Count - 1 To 0 Step -1
            If Now.Subtract(Me.Context.LiveProgramList(i).StartDateTime).Minutes > 30 Then
                Me.Context.LiveProgramList.RemoveAt(i)
            End If
        Next

        ' 再クロール待機
        CrawlPages(1)

    End Sub

    Private Sub SaveSettings()

        Dim document = <?xml version="1.0" encoding="utf-8"?>
                       <settings></settings>
        Dim settings = Me.Context.UserSettings
        Try
            Dim el = document.<settings>.First
            el.Add(<alerts>
                       <window><%= settings.AlertWindowEnabled %></window>
                       <balloon><%= settings.BalloonEnabled %></balloon>
                       <web><%= settings.WebOpeningEnabled %></web>
                       <browserPath><%= settings.WebBrowserPath %></browserPath>
                       <email><%= settings.EmailEnabled %></email>
                       <address><%= settings.Email %></address>
                       <server><%= settings.SmtpServer %></server>
                       <port><%= settings.Port %></port>
                       <sound><%= settings.SoundEnabled %></sound>
                       <soundFile><%= settings.SoundFile %></soundFile>
                   </alerts>)
            el.Add(<ui>
                       <windowWidth><%= Me.Width %></windowWidth>
                       <windowHeight><%= Me.Height %></windowHeight>
                       <program>
                           <title><%= settings.ProgramListViewTitleHeaderWidth %></title>
                           <community><%= settings.ProgramListViewCommunityHeaderWidth %></community>
                           <datetime><%= settings.ProgramListViewStartDateTimeHeaderWidth %></datetime>
                           <visitor><%= settings.ProgramListViewVisitorCountHeaderWidth %></visitor>
                           <comment><%= settings.ProgramListViewCommentCountHeaderWidth %></comment>
                           <public><%= settings.ProgramListViewMemberOnlyHeaderWidth %></public>
                           <content><%= settings.ProgramListViewContentHeaderWidth %></content>
                       </program>
                       <community>
                           <onair><%= settings.CommunityListViewOnAirHeaderWidth %></onair>
                           <name><%= settings.CommunityListViewNameHeaderWidth %></name>
                           <airdate><%= settings.CommunityListViewAirdateHeaderWidth %></airdate>
                       </community>
                   </ui>)
            Dim file = System.IO.Path.Combine(MainWindow.StartupPath, My.Resources.UserSettingsFile)
            document.Save(file)

        Catch ex As Exception
            ' Ignore
#If DEBUG Then
            Stop
#End If
        End Try

    End Sub

    Private Sub LoadSettings()

        ' Crawl Settings
        Try
            Dim document = XDocument.Load(My.Resources.CrawlSettingsFile)
            For Each el In document...<uri>
                Me.CrawlSettings.Uris.Add(New Uri(el.Value))
            Next
            Me.CrawlSettings.RegexPattern = document.<settings>.<regexPattern>.Value

        Catch ex As Exception
#If DEBUG Then
            Stop
#End If
        End Try

        ' User Settings
        Dim file = System.IO.Path.Combine(MainWindow.StartupPath, My.Resources.UserSettingsFile)
        If Not System.IO.File.Exists(file) Then
            Me.Context.UserSettings.AlertWindowEnabled = True
            Exit Sub
        End If

        Try
            Dim document = XDocument.Load(file)
            Dim alerts = document.<settings>.<alerts>
            If alerts.Count > 0 Then
                Dim alert = alerts.First
                With Me.Context.UserSettings
                    .AlertWindowEnabled = CBool(alert.<window>.Value)
                    .BalloonEnabled = CBool(alert.<balloon>.Value)
                    .WebOpeningEnabled = CBool(alert.<web>.Value)
                    .WebBrowserPath = CStr(alert.<browserPath>.Value)
                    .EmailEnabled = CBool(alert.<email>.Value)
                    .Email = alert.<address>.Value
                    .SmtpServer = alert.<server>.Value
                    .SoundEnabled = CBool(alert.<sound>.Value)
                    .SoundFile = alert.<soundFile>.Value
                End With
                If Not String.IsNullOrEmpty(alert.<port>.Value) Then
                    Me.Context.UserSettings.Port = CInt(alert.<port>.Value)
                Else
                    Me.Context.UserSettings.Port = 25
                End If
            End If


            Dim uis = document.<settings>.<ui>
            If uis.Count > 0 Then
                Dim ui = uis.First
                Dim width As Double
                Dim height As Double

                width = CDbl(ui.<windowWidth>.Value)
                If width >= Me.MinWidth Then
                    Me.Width = width
                End If

                height = CDbl(ui.<windowHeight>.Value)
                If height >= Me.MinHeight Then
                    Me.Height = height
                End If

                Dim programs = ui.<program>
                If programs.Count > 0 Then
                    Dim p = programs.First

                    If p.<title>.Value <> "NaN" Then
                        width = CDbl(p.<title>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.ProgramListViewTitleHeaderWidth = width
                        End If
                    End If

                    If p.<community>.Value <> "NaN" Then
                        width = CDbl(p.<community>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.ProgramListViewCommunityHeaderWidth = width
                        End If
                    End If

                    If p.<datetime>.Value <> "NaN" Then
                        width = CDbl(p.<datetime>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.ProgramListViewStartDateTimeHeaderWidth = width
                        End If
                    End If

                    If p.<visitor>.Value <> "NaN" Then
                        width = CDbl(p.<visitor>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.ProgramListViewVisitorCountHeaderWidth = width
                        End If
                    End If

                    If p.<comment>.Value <> "NaN" Then
                        width = CDbl(p.<comment>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.ProgramListViewCommentCountHeaderWidth = width
                        End If
                    End If

                    If p.<public>.Value <> "NaN" Then
                        width = CDbl(p.<public>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.ProgramListViewMemberOnlyHeaderWidth = width
                        End If
                    End If

                    If p.<content>.Value <> "NaN" Then
                        width = CDbl(p.<content>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.ProgramListViewContentHeaderWidth = width
                        End If
                    End If

                End If

                Dim communities = uis.<community>
                If communities.Count > 0 Then
                    Dim c = communities.First

                    If c.<onair>.Value <> "NaN" Then
                        width = CDbl(c.<onair>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.CommunityListViewOnAirHeaderWidth = width
                        End If
                    End If

                    If c.<name>.Value <> "NaN" Then
                        width = CDbl(c.<name>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.CommunityListViewNameHeaderWidth = width
                        End If
                    End If

                    If c.<airdate>.Value <> "NaN" Then
                        width = CDbl(c.<airdate>.Value)
                        If width > 0 Then
                            Me.Context.UserSettings.CommunityListViewAirdateHeaderWidth = width
                        End If
                    End If

                End If
            End If



            'For Each el In document...<uri>
            '    Me.CrawlSettings.Uris.Add(New Uri(el.Value))
            'Next
            'Me.CrawlSettings.RegexPattern = document.<settings>.<regexPattern>.Value

        Catch ex As Exception
#If DEBUG Then
            Stop
#End If
        End Try


    End Sub

    Private Sub SaveCommunityList()

        Dim document = <?xml version="1.0" encoding="utf-8"?>
                       <communities xmlns="http://ch.nicovideo.jp/community/co9320">
                       </communities>

        Try
            For Each c In Me.Context.CommunityList
                document.<communities>.First.Add(<community>
                                                     <id><%= c.Id %></id>
                                                     <name><%= c.Name %></name>
                                                     <iconUri><%= c.IconUri.ToString %></iconUri>
                                                     <recentAirdate><%= c.RecentAirdate.ToOADate %></recentAirdate>
                                                 </community>)

            Next
            Dim file = System.IO.Path.Combine(MainWindow.StartupPath, My.Resources.CommunityListFile)
            document.Save(file)

        Catch ex As Exception
            ' Ignore
#If DEBUG Then
            Stop
#End If
        End Try


    End Sub

    Private Sub LoadCommunityList()

        Dim file = System.IO.Path.Combine(MainWindow.StartupPath, My.Resources.CommunityListFile)
        If Not System.IO.File.Exists(file) Then
            Exit Sub
        End If

        Try
            Dim document = XDocument.Load(file)
            For Each el In From e In document...<community> Where e.<id>.Value <> ""
                Try
                    Dim c = New Community With {.Id = el.<id>.Value, _
                                                .Name = el.<name>.Value, _
                                                .IconUri = New Uri(el.<iconUri>.Value), _
                                                .RecentAirdate = DateTime.FromOADate(CDbl(el.<recentAirdate>.Value))}
                    Me.Context.CommunityList.Add(c)

                Catch ex As Exception
                    ' Ignore
#If DEBUG Then
                    Stop
#End If
                End Try
            Next
        Catch ex As Exception
            ' Ignore
#If DEBUG Then
            Stop
#End If
        End Try
    End Sub

    Private Function GetContent(ByVal uri As Uri) As String

        Dim request = DirectCast(WebRequest.Create(uri), HttpWebRequest)

        request.UserAgent = ""

        Dim content As String = ""
        Try
            Dim response = request.GetResponse
            Using stream = response.GetResponseStream, _
                  reader = New System.IO.StreamReader(stream, System.Text.Encoding.UTF8)
                content = reader.ReadToEnd
            End Using
        Catch webEx As WebException
            ' Ignore

        End Try
        Return content

    End Function

#Region "ListView events"

    'Private Sub ListViewItem_MouseDoubleClick(ByVal sender As Object, _
    '                                      ByVal e As MouseButtonEventArgs)
    '    If e.ChangedButton <> MouseButton.Left Then
    '        Exit Sub
    '    End If



    '    If sender Is CommunitiesListView Then
    '        CommunitiesListView_MouseDoubleClick(Me, e)
    '    ElseIf sender Is LiveProgramListView Then
    '        LiveProgramListView_MouseDoubleClick(Me, e)
    '    End If
    'End Sub


    Private Sub CommunitiesListView_MouseDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)

        If e.ChangedButton <> MouseButton.Left Then
            Exit Sub
        End If

        If Me.CommunitiesListView.SelectedIndex < 0 Then
            Exit Sub
        End If

        Dim element = DirectCast(CommunitiesListView.ItemContainerGenerator.ContainerFromItem(Me.CommunitiesListView.SelectedItem), UIElement)
        If element Is Nothing OrElse element.InputHitTest(e.GetPosition(element)) Is Nothing Then
            Exit Sub
        End If

        Dim community = DirectCast(Me.CommunitiesListView.SelectedItem, Community)
        Dim uri As Uri = Nothing

        If community.IsOnAir Then
            Dim programs = From p In Me.Context.LiveProgramList Where p.Community.Id = community.Id
            If programs.Count > 0 Then
                uri = programs.First.Uri
            End If
        Else
            uri = community.Uri
        End If

        Alerter.OpenUri(uri)

    End Sub

    Private Sub LiveProgramListView_MouseDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)

        If e.ChangedButton <> MouseButton.Left Then
            Exit Sub
        End If

        If Me.LiveProgramListView.SelectedIndex < 0 Then
            Exit Sub
        End If

        Dim element = DirectCast(LiveProgramListView.ItemContainerGenerator.ContainerFromItem(Me.LiveProgramListView.SelectedItem), UIElement)
        If element Is Nothing OrElse element.InputHitTest(e.GetPosition(element)) Is Nothing Then
            Exit Sub
        End If


        Dim program = DirectCast(Me.LiveProgramListView.SelectedItem, LiveProgram)
        Alerter.OpenUri(program.Uri)

    End Sub

#End Region

#Region "Commands"

    Private Sub AddStationsCommand_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)
        For Each program As LiveProgram In LiveProgramListView.SelectedItems

            Dim id = program.Community.Id
            If (From c In Context.CommunityList Where c.Id = id).Count = 0 Then
                program.Community.IsSelected = False
                Me.Context.CommunityList.Add(program.Community) ' コミュListに登録

                ' 登録した生放送中の番組は通知対象としない
                Alerter.AlertedProgramIds.Add(program.Id)

            End If
        Next

        CommunityTabItem.IsSelected = True
    End Sub

    Private Sub ForDataGridRowsCommand_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)

        If e.Source Is LiveProgramListView Then
            If LiveProgramListView.SelectedItems.Count > 0 Then
                e.CanExecute = True
            End If
        ElseIf e.Source Is CommunitiesListView Then
            If CommunitiesListView.SelectedItems.Count > 0 Then
                e.CanExecute = True
            End If
        End If

    End Sub

    Private Sub ForOnlyDataGridRowCommand_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)

        If e.Source Is LiveProgramListView Then
            If LiveProgramListView.SelectedItems.Count = 1 Then
                e.CanExecute = True
            End If
        ElseIf e.Source Is CommunitiesListView Then
            If CommunitiesListView.SelectedItems.Count = 1 Then
                e.CanExecute = True
            End If
        End If

    End Sub

    Private Sub OpenUrisCommand_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        Dim parameter = CStr(e.Parameter)

        Dim uris = New List(Of Uri)
        Select Case parameter
            Case "program"
                For Each p As LiveProgram In LiveProgramListView.SelectedItems
                    uris.Add(p.Uri)
                Next
            Case "liveprogram"
                For Each c As Community In CommunitiesListView.SelectedItems
                    If c.IsOnAir Then
                        Dim id = c.Id
                        Dim programs = Me.Context.LiveProgramList.Where(Function(p) p.Community.Id = id)
                        If programs.Count > 0 Then
                            uris.Add(programs.First.Uri)
                        End If
                    End If
                Next
            Case "station"
                For Each c As Community In CommunitiesListView.SelectedItems
                    uris.Add(c.Uri)
                Next
            Case Else
                Exit Sub
        End Select

        If uris.Count >= 5 Then
            If CenterMessageBox.Show(Me, "5個以上選択されています。開きますか？", My.Resources.ApplicationName, MessageBoxButton.YesNo, MessageBoxImage.Information, MessageBoxResult.No) = MessageBoxResult.No Then
                Exit Sub
            End If
        End If

        For Each u In uris
            Alerter.OpenUri(u)
        Next
    End Sub

    Private Sub CopyUriCommand_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        Dim parameter = CStr(e.Parameter)

        Dim uri As Uri = Nothing
        Select Case parameter
            Case "program"
                uri = DirectCast(LiveProgramListView.SelectedItem, LiveProgram).Uri
            Case "liveprogram"
                For Each c As Community In CommunitiesListView.SelectedItems
                    If c.IsOnAir Then
                        Dim id = c.Id
                        Dim programs = Me.Context.LiveProgramList.Where(Function(p) p.Community.Id = id)
                        If programs.Count > 0 Then
                            uri = programs.First.Uri
                            Exit For
                        End If
                    End If
                Next
            Case "station"
                uri = DirectCast(CommunitiesListView.SelectedItem, Community).Uri
            Case Else
                Exit Sub
        End Select

        Try
            Clipboard.SetText(uri.ToString)
        Catch ex As Exception
            ' Ignore
        End Try
    End Sub

    Private Sub DeleteStationsCommand_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        If CenterMessageBox.Show(Me, "削除します。よろしいですか？", My.Resources.ApplicationName, MessageBoxButton.YesNo, MessageBoxImage.Information, MessageBoxResult.No) = MessageBoxResult.No Then
            Exit Sub
        End If

        For i = CommunitiesListView.SelectedItems.Count - 1 To 0 Step -1
            Dim c = DirectCast(CommunitiesListView.SelectedItems(i), Community)
            Me.Context.CommunityList.Remove(c)
        Next

    End Sub



    'Private Sub SubscribeCommandBinding_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

    '    For Each program As LiveProgram In LiveProgramListView.Items

    '        If program.IsSelected Then
    '            Dim id = program.Community.Id
    '            If (From c In Context.CommunityList Where c.Id = id).Count = 0 Then
    '                program.Community.IsSelected = False
    '                Me.Context.CommunityList.Add(program.Community) ' コミュListに登録

    '                ' 登録した生放送中の番組は通知対象としない
    '                Alerter.AlertedProgramIds.Add(program.Id)

    '            End If
    '            program.IsSelected = False
    '        End If
    '    Next

    '    CommunityTabItem.IsSelected = True
    '    SaveCommunityList()

    'End Sub

    'Private Sub SubscribeCommandBinding_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)

    '    If (From p In Me.Context.LiveProgramList Where p.IsSelected).Count > 0 Then
    '        e.CanExecute = True
    '    End If
    'End Sub

    'Private Sub DeleteCommandBinding_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

    '    For i = CommunitiesListView.Items.Count - 1 To 0 Step -1
    '        Dim c = DirectCast(CommunitiesListView.Items(i), Community)
    '        If c.IsSelected Then
    '            Me.Context.CommunityList.Remove(c)
    '        End If
    '    Next

    '    SaveCommunityList()

    'End Sub

    'Private Sub DeleteCommandBinding_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)
    '    If (From p In Me.Context.CommunityList Where p.IsSelected).Count > 0 Then
    '        e.CanExecute = True
    '    End If
    'End Sub
#End Region

    'Private Sub GridViewColumnHeaderClickedHandler(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

    '    If Not TypeOf e.OriginalSource Is GridViewColumnHeader Then
    '        Exit Sub
    '    End If

    '    Dim headerClicked = DirectCast(e.OriginalSource, GridViewColumnHeader)
    '    Dim header = CStr(headerClicked.Column.Header)

    '    If header = "" Then
    '        Exit Sub
    '    End If

    '    Dim direction As ListSortDirection

    '    If headerClicked Is Nothing OrElse headerClicked.Role = GridViewColumnHeaderRole.Padding Then
    '        Exit Sub
    '    End If

    '    If headerClicked IsNot _lastHeaderClicked Then
    '        direction = ListSortDirection.Ascending
    '    Else
    '        direction = If(_lastDirection = ListSortDirection.Ascending, ListSortDirection.Descending, ListSortDirection.Ascending)
    '    End If

    '    Dim propertyName As String = ""
    '    Select Case header
    '        Case "タイトル"
    '            propertyName = "Title"
    '        Case "コミュニティ"
    '            propertyName = "Community.Name"
    '        Case "開始時間"
    '            propertyName = "StartDateTime"
    '        Case "来場者数"
    '            propertyName = "VisitorCount"
    '        Case "コメ数"
    '            propertyName = "CommentCount"
    '    End Select
    '    If propertyName = "" Then
    '        Exit Sub
    '    End If

    '    Sort(propertyName, direction)

    '    'If direction = ListSortDirection.Ascending Then
    '    '    headerClicked.Column.HeaderTemplate = DirectCast(Resources("HeaderTemplateArrowUp"), DataTemplate)
    '    'Else
    '    '    headerClicked.Column.HeaderTemplate = DirectCast(Resources("HeaderTemplateArrowDown"), DataTemplate)
    '    'End If

    '    ' Remove arrow from previously sorted header
    '    If _lastHeaderClicked IsNot Nothing AndAlso _lastHeaderClicked IsNot headerClicked Then
    '        _lastHeaderClicked.Column.HeaderTemplate = Nothing
    '    End If

    '    _lastHeaderClicked = headerClicked
    '    _lastDirection = direction
    'End Sub

    'Private Sub Sort(ByVal sortBy As String, ByVal direction As ListSortDirection)
    '    Dim dataView = CollectionViewSource.GetDefaultView(LiveProgramListView.ItemsSource)

    '    dataView.SortDescriptions.Clear()
    '    Dim sd = New SortDescription(sortBy, direction)
    '    dataView.SortDescriptions.Add(sd)
    '    dataView.Refresh()

    'End Sub

    Private Sub ReloadButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        'Me.ReloadButton.IsEnabled = False
        Crawler.CancelAsync()
        CrawlPages(0)
    End Sub

#Region "Form events"

    Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Me.Title = My.Resources.ApplicationName


        ShowNotifyIcon()

        LoadCommunityList()
        LoadSettings()

        Alerter.SetNotifyIcon(Me.NotifyIcon)
        Alerter.SetUserSetting(Me.Context.UserSettings)

        IsLoaded = True

        CrawlPages(0)

    End Sub

    Private Sub MainWindow_StateChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.StateChanged

        If Me.WindowState = Windows.WindowState.Minimized Then
            Me.ShowInTaskbar = False
        Else
            Me.ShowInTaskbar = True
        End If
    End Sub

    Private Sub MainWindow_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles Me.Closing


        If IsLoaded Then
            NotifyIcon.Visible = False
            SaveSettings()
            SaveCommunityList()
        End If

    End Sub


#End Region

#Region "NotifyIcon"

    Private WithEvents NotifyIcon As Forms.NotifyIcon

    Private Sub ExitMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs)
        Me.Close()
    End Sub

    Private Sub ShowNotifyIcon()

        If NotifyIcon Is Nothing Then
            NotifyIcon = New Forms.NotifyIcon
        End If

        Dim menu = New Forms.ContextMenu
        menu.MenuItems.Add("終了", AddressOf ExitMenuItem_Click)

        NotifyIcon.Icon = My.Resources.notifyIcon
        NotifyIcon.Text = My.Resources.ApplicationName
        NotifyIcon.Visible = True
        NotifyIcon.ContextMenu = menu

    End Sub



    Private Sub NotifyIcon_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles NotifyIcon.DoubleClick
        Me.WindowState = Windows.WindowState.Normal
        Me.Activate()
    End Sub

#End Region

#Region "IDisposable Interface"

    Private disposedValue As Boolean = False        ' 重複する呼び出しを検出するには

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: 他の状態を解放します (マネージ オブジェクト)。
                If Crawler IsNot Nothing Then
                    Crawler.CancelAsync()
                    Crawler.Dispose()
                End If
            End If

            ' TODO: ユーザー独自の状態を解放します (アンマネージ オブジェクト)。
            ' TODO: 大きなフィールドを null に設定します。
        End If
        Me.disposedValue = True
    End Sub

#Region " IDisposable Support "
    ' このコードは、破棄可能なパターンを正しく実装できるように Visual Basic によって追加されました。
    Public Sub Dispose() Implements IDisposable.Dispose
        ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

#End Region

    Private Sub SettingsButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

        Dim window = New SettingsWindow With {.DataContext = Me.Context.UserSettings, _
                                              .Owner = Me}
        window.ShowDialog()

    End Sub

    'Private Sub CommunityListViewColumnCheckBox_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    '    Dim checkBox = DirectCast(sender, CheckBox)
    '    For Each c In Me.Context.CommunityList
    '        c.IsSelected = CBool(checkBox.IsChecked)
    '    Next
    'End Sub
End Class
